home *** CD-ROM | disk | FTP | other *** search
Text File | 1995-03-30 | 14.7 KB | 579 lines | [TEXT/MMCC] |
- //\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/
- //
- // Utils.c
- //
- // Utility functions.
- //
- // History:
- //
- // 950221jb: created abridged set of utility functions for demo projects
- //
- //\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/
-
-
- // __#Defines________________________________________________________________________
- #define kSleepTicks 0xFFFFFFFF //relinquish all time; don't want null events
-
- #define kGestaltTrapNumber 0xA1AD
- #define kInitGrafTrapNumber 0xA86E
- #define kUnimplementedTrapNumber 0x9F
-
- #define kOurStopAlertID 999 //ID of ALRT resource
-
- #define kIndexedGDeviceType 0
- #define kFixedGDeviceType 1
- #define kDirectGDeviceType 2
-
- // __#Headers________________________________________________________________________
- #include "Utils.h"
-
- // __#Protos_________________________________________________________________________
- // __ Macros_________________________________________________________________________
- // __ Enums__________________________________________________________________________
- // __ Typedefs_______________________________________________________________________
- // __ Static Protos__________________________________________________________________
- static Boolean TrapAvailable( short theTrap );
-
- // __ Extern Globals_________________________________________________________________
- RGBColor blackRGB = {0, 0, 0};
- RGBColor grayRGB = {32767, 32767, 32767};
- RGBColor whiteRGB = {65535, 65535, 65535};
-
- // __ Static Globals_________________________________________________________________
-
- // __ Functions______________________________________________________________________
-
-
-
-
- //____ ToolBoxInit __________________________________________________________________________
- //
- // Basic initialization.
- //
- void ToolBoxInit( void )
- {
- InitGraf(&qd.thePort);
- InitFonts();
- InitWindows();
- InitMenus();
- TEInit();
- InitDialogs(NULL);
- InitCursor();
- FlushEvents(everyEvent, 0);
- }//ToolBoxInit
-
-
- //____ WaitForQuit __________________________________________________________________________
- //
- // Hangs out until there is any keyboard or mouse activity. This
- // is not a very friendly or robust event loop! For demo only!
- //
- void WaitForQuit( void )
- {
- Boolean wait;
- EventRecord theEvent;
-
- wait = TRUE;
- while (wait)
- {
- if(WaitNextEvent(everyEvent, &theEvent, kSleepTicks, 0L))
- {
- switch (theEvent.what)
- {
- case mouseDown:
- case keyDown:
- wait = FALSE;
- break;
- }//switch (theEvent.what)
- }//if WaitNextEvent
- }//while
-
- }//WaitForQuit
-
-
- //____ TrapAvailable __________________________________________________________________________
- //
- // Determines if a given trap exists on the Macintosh we're running on.
- //
- static Boolean TrapAvailable( short theTrap )
- {
- TrapType theTrapType; // Trap type
- short numTraps; // Number of Toolbox traps
- Boolean trapAvail; // True if the trap is available, false if not.
-
- if ( ( theTrap & 0x0800 ) > 0 )
- theTrapType = ToolTrap;
- else
- theTrapType = OSTrap;
-
- if ( theTrapType == ToolTrap )
- {
- theTrap = theTrap & 0x07FF;
-
- if ( NGetTrapAddress( kInitGrafTrapNumber, ToolTrap ) == NGetTrapAddress( 0xAA6E, ToolTrap ) )
- numTraps = 0x0200;
- else
- numTraps = 0x0400;
-
- if ( theTrap >= numTraps )
- theTrap = kUnimplementedTrapNumber;
- }
-
- trapAvail = NGetTrapAddress( theTrap, theTrapType ) != NGetTrapAddress( kUnimplementedTrapNumber, ToolTrap );
-
- return(trapAvail);
-
- }// TrapAvailable
-
-
-
-
- //____ EnviroCheck __________________________________________________________________________
- //
- // This checks out the current system and tells us if the amenities we
- // require are available.
- //
- // For our demos, we're insist on System Seven and a Main Device which is
- // color-capable not in black-and-white mode.
- //
- Boolean EnviroCheck( void )
- {
- Boolean returnMe = FALSE;
- GDHandle theMainGDev;
- long theSystemVersion;
-
- //determine if Gestalt is available…
- if (!TrapAvailable( kGestaltTrapNumber ))
- {
- ShowStopAlert( "\pGestalt trap unavailable on this System." );
- goto Xit;
- }
-
- //Make sure we have at least a minimal System level of functionality
- Gestalt( gestaltSystemVersion, &theSystemVersion );
-
- //We are requiring System Seven
- if ( LoWord( theSystemVersion ) < 0x0700 ) // Check for System Seven
- {
- ShowStopAlert( "\pThe System installed is earlier than System Seven." );
- goto Xit;
- }
-
- // Note: Since we're requiring System Seven, we don't have to wonder if
- // 32-Bit QuickDraw is installed. However, if you must be backwards
- // compatible, you can do an explicit check for it:
- //
- // Gestalt( gestaltQuickdrawVersion, &qdVersion );
- // if ( qdVersion < gestalt32BitQD ) // Some version of 32 Bit Color Quickdraw present...
- // {
- // ShowStopAlert( "\pAaaack! For some reason we need 32-Bit QuickDraw and it's not here!" );
- // goto Xit;
- // }
-
-
- theMainGDev = GetMainDevice();
- // Our demos won't have a problem if the Main GDevice is a Fixed device, but if you want to
- // determine if the main GDevice is a Fixed type (like on PowerBooks), here's how:
- // if (kFixedGDeviceType == (**theMainGDev).gdType)
- // {
- // ShowStopAlert( "\pMain GDevice is a Fixed Device." );
- // goto Xit;
- // }
-
- // Is this screen black-and-white, or in color/grayscale mode?
- if ( 0 == TestDeviceAttribute( theMainGDev, gdDevType ) )
- {
- ShowStopAlert( "\pThis demo must run in color." );
- goto Xit;
- }
-
- //Could use HasDepth to determine depth of the monitor, but for our
- //demos we're letting QuickDraw handle color translation.
-
- returnMe = TRUE;
- Xit:
- return returnMe;
- }//EnviroCheck
-
-
- //____ ShowStopAlert __________________________________________________________________________
- //
- // This puts up a Stop Alert. The passed Pascal-style string is ParamText'ed into
- // a small static-text area in the Alert and is appended with "Application halts."
- //
- void ShowStopAlert(StringPtr pascalMessage)
- {
- short dummy;
- ParamText(pascalMessage, "\p Application halts.", "\p", "\p");
- dummy = StopAlert(kOurStopAlertID,NULL);
- }//ShowStopAlert
-
-
-
- //____ GetAppName __________________________________________________________________________
- //
- // Uses the Process Manager to find out our App's Name
- // (better than using CurAppName lo-mem global, which
- // may break.) Call this once, during startup procedure.
- //
- void GetAppName(char *pascalName)
- {
- OSErr err;
- ProcessSerialNumber PSN;
- ProcessInfoRec info;
-
- //get serial number of our process
- err = GetCurrentProcess(&PSN);
- if (noErr != err)
- goto Xit;
-
- //funkyness here is required for GetProcessInformation()
- info.processInfoLength = sizeof( ProcessInfoRec );
- info.processAppSpec = nil;
- info.processName = ( StringPtr ) pascalName;
-
- //learn a bunch of interesting things about our process,
- //including it's name
- err = GetProcessInformation(&PSN,&info);
-
- Xit:
- if (noErr != err)
- {
- BlockMove("\8Untitled", pascalName, 9);
- }
-
- return;
-
- }//GetAppName
-
-
- //____ InitRandomNumbers __________________________________________________________________________
- //
- void InitRandomNumbers( void )
- {
- GetDateTime((unsigned long *)&qd.randSeed);
- }//InitRandomNumbers
-
- //____ RandomRange __________________________________________________________________________
- //
- // Given an unsigned short, this returns a value between zero and range - 1.
- //
- unsigned short RandomRange( unsigned short range )
- {
- long aLong; //treat return value as 0-65536
-
- aLong = Random();
- aLong += 32767;
- return (aLong * range) / 65536; // now 0 <= t < range
- }//RandomRange
-
-
- //____ GlobalToLocalRect __________________________________________________________________________
- //
- // Changes passed rectangle from Global to Local coördinates.
- //
- void GlobalToLocalRect(Rect *r)
- {
- GlobalToLocal(&mTopLeft(*r));
- GlobalToLocal(&mBotRight(*r));
- }//GlobalToLocalRect
-
-
- //____ LocalToGlobalRect __________________________________________________________________________
- //
- // Changes passed rectangle from Local to Global coördinates.
- //
- void LocalToGlobalRect(Rect *r)
- {
- LocalToGlobal(&mTopLeft(*r));
- LocalToGlobal(&mBotRight(*r));
- }//LocalToGlobalRect
-
-
- //____ CenterRectInRect __________________________________________________________________________
- //
- // Centers rect1 in rect2
- //
- void CenterRectInRect(Rect *rect1, Rect *rect2)
- {
- mAssert((NULL != rect1) && (NULL != rect2));
-
- OffsetRect (rect1,
- ((rect2->right - rect2->left) - (rect1->right - rect1->left))/2 - rect1->left,
- ((rect2->bottom - rect2->top) - (rect1->bottom - rect1->top))/2 - rect1->top);
- }//CenterRectInRect
-
-
- //____ CenterWindowInRect __________________________________________________________________________
- //
- // Serviceable centering code; will center dialogs, too.
- // Note that we ignore menubar height.
- //
- // Incidentally, windows look nicer if they're centered horizontally and
- // 1/3 of the way down from the top of the screen. Pass in TRUE for oneThird,
- // and that's where the window will wind up; pass in FALSE and window will
- // be centered square in the middle of boundRect.
- //
- //
- void CenterWindowInRect(WindowPtr wind, Rect *boundRect, Boolean oneThird)
- {
- Rect windRect, bounds;
-
- mAssert(NULL != wind);
- mAssert(NULL != boundRect);
-
- if ((NULL == wind) || (NULL == boundRect))
- return;
-
- //It's better if we can get use the structure rect for centering,
- //but we won't fuss around if we can't get it. (You could be
- //clever and move the window way off somewhere, show it, grab the
- //structure bounds, hide the window, and offset both objects back
- //to where they ought to be.)
- if (((WindowPeek)wind)->visible)
- windRect = (*(((WindowPeek)wind)->strucRgn))->rgnBBox;
- else
- windRect = wind->portRect;
-
- bounds = *boundRect;
-
- mAssert(!EmptyRect(&bounds));
- mAssert(!EmptyRect(&windRect));
-
- if (oneThird)
- {
- MoveWindow(wind, ((bounds.right - bounds.left) - (windRect.right - windRect.left))/2 + bounds.left,
- ((bounds.bottom - bounds.top) - (windRect.bottom - windRect.top))/3 + bounds.top,
- TRUE);
- }
- else
- {
- CenterRectInRect(&windRect, &bounds);
- MoveWindow(wind, windRect.left, windRect.top, TRUE);
- }
-
- }//CenterWindowInRect
-
-
- //____ GetMaxIntersectDevice __________________________________________________________________________
- //
- // Given a rectangle in global coördinates, this will return the device
- // on which the majority of the rectangle overlaps.
- //
- GDHandle GetMaxIntersectDevice(Rect globalRect)
- {
- long area, maxArea; //must be longs; shorts may overflow.
- GDHandle device, deviceToReturn;
- Rect intersection;
-
- deviceToReturn = GetMainDevice();
- maxArea = 0;
-
- for (device = GetDeviceList(); device != NULL ; device = GetNextDevice(device))
- {
- //determine if device is a screen, if it's active, and our rect intersects it
- if ((TestDeviceAttribute(device, screenDevice)
- && TestDeviceAttribute(device, screenActive)
- && SectRect(&globalRect, &((*device)->gdRect), &intersection)))
- {
- area = ((long)(intersection.right - intersection.left)) *
- ((long)(intersection.bottom - intersection.top));
- if (area > maxArea)
- {
- deviceToReturn = device;
- maxArea = area;
- }
- }
- }
- return(deviceToReturn);
- }//GetMaxIntersectDevice
-
-
- //____ GetLargestAreaDevice __________________________________________________________________________
- //
- // Returns device with largest area.
- //
- GDHandle GetLargestAreaDevice( void )
- {
- long area, maxArea; //make sure these are longs!!
- GDHandle device, deviceToReturn;
-
- deviceToReturn = GetMainDevice();
- maxArea = 0;
-
- for (device = GetDeviceList(); device != NULL ; device = GetNextDevice(device))
- {
- //determine if device is a screen, and if it's active
- if ((TestDeviceAttribute(device, screenDevice)
- && TestDeviceAttribute(device, screenActive)))
- {
- area = ((long)(*device)->gdRect.bottom - (*device)->gdRect.top)
- * ((long)(*device)->gdRect.right - (*device)->gdRect.left);
- if (area > maxArea)
- {
- deviceToReturn = device;
- maxArea = area;
- }
- }
- }
-
- return(deviceToReturn);
-
- }//GetLargestAreaDevice
-
-
- //____ CountAvailableDevices __________________________________________________________________________
- //
- // Walks thru public GDevice list and tells us how many active screens there are
- //
- short CountAvailableDevices( void )
- {
- short count = 0;
- GDHandle aDevice;
-
- for (aDevice = GetDeviceList(); aDevice != NULL ; aDevice = GetNextDevice(aDevice))
- {
- if ( (TestDeviceAttribute(aDevice, screenDevice))
- && (TestDeviceAttribute(aDevice, screenActive)))
- count += 1;
- }
-
- mAssert(count > 0);
-
- return count;
-
- }//CountAvailableDevices
-
-
-
-
- #pragma mark -
- // string utils
-
-
-
- //____ CLen __________________________________________________________________________
- //
- // Returns length of C string; analogous to strlen.
- //
- long CLen(char *s)
- {
- char *p;
- long len;
-
- p = s;
- while (*p++ != '\0')
- ;//twiddle
-
- len = (--p - s);
-
- return(len);
- }//CLen
-
-
- //____ PLen __________________________________________________________________________
- //
- // Returns length of Pascal string.
- //
- short PLen(StringPtr s)
- {
- mAssert(*s >= 0);
- return ((short)*s); //Pascal strings store lenght in first byte
- }//PLen
-
-
- //____ Pas2c __________________________________________________________________________
- //
- // Converts a string from Pascal to C in place
- //
- char *Pas2c(unsigned char *str)
- {
- unsigned short len;
-
- len = str[0];
- mAssert ((len >= 0) || (len <= 255));
- if ((len < 0) || (len > 255)) //insanity check -- do something reasonable
- len = 255;
- BlockMove(str + 1, str, len); //BlockMove properly handles overlapping blocks
- str[len] = '\0';
-
- return((char *)str);
- }//Pas2c
-
-
- //____ C2pas __________________________________________________________________________
- //
- // Converts a C string into Pascal variety. Will truncate to 255 chars if needed.
- //
- unsigned char *C2pas(char *str)
- {
-
- long len;
-
- len = CLen(str);
-
- if ((len < 0) || (len > 255))
- len = 255;
-
- BlockMove(str, str + 1, len); //BlockMove properly handles overlapping blocks
- str[0] = len;
- return((unsigned char *)str);
-
- }//C2pas
-
-
-
- //____ CCpy __________________________________________________________________________
- //
- // analogous to ccpy
- //
- char *CCpy(char *dest, char *src)
- {
- long len;
-
- len = CLen(src);
-
- BlockMove(src, dest, len + 1);
-
- return(dest);
- }
-
-
-
- //____ PCpy __________________________________________________________________________
- //
- // Copies Pascal string from src to dest
- //
- unsigned char *PCpy(StringPtr dest, StringPtr src)
- {
- long len;
-
- len = PLen(src);
-
- BlockMove(src, dest, len + 1);
-
- return(dest);
- }
-
-
- //____ CWrite __________________________________________________________________________
- //
- // Draws Pascal string centered on x, with baseline at y
- //
- void CWrite( short x, short y, ConstStr255Param s )
- {
- MoveTo(x - StringWidth(s) / 2, y);
- DrawString(s);
- }
-
-
-
- //____ ParamAString __________________________________________________________________________
- //
- // This convenient routine allows you to param a single Pascal string.
- //
- void ParamAString( ConstStr255Param theStr )
- {
- ParamText(theStr, "\p", "\p", "\p");
- } //ParamAString
-